#ifndef INI_FILE_STREAM_READER_H
#define INI_FILE_STREAM_READER_H

#include <iostream>

namespace IniFile
{

class StreamReader
{
    unsigned int prevColumn_;
    unsigned long row_;
    unsigned int column_;
    std::istream *inputStream_;
protected:
    StreamReader(std::istream *inputStream) : inputStream_(inputStream)
    {
		rewindInputStream();
    }
    int getChar()
    {
        if (inputStream_ == 0)
            return std::istream::traits_type::eof();
        enum { START, WINDOWS_NEWLINE, UNIX_NEWLINE } state = START;
        int c;
        while ("no char found")
            switch (state)
            {
            case START:
                switch (c = inputStream_->get())
                {
                case '\r':
                    state = WINDOWS_NEWLINE;
                    break;
                case '\n':
                    state = UNIX_NEWLINE;
                    break;
                default:
                    column_++;
                    return c;
                }
            case WINDOWS_NEWLINE:
                if ((c = inputStream_->get()) != '\n')
                    inputStream_->putback(c);
            case UNIX_NEWLINE:
                row_++;
                prevColumn_ = column_;
                column_ = 1;
                return '\n';
            }
        return std::istream::traits_type::eof();
    }
    bool putBackChar(int c)
    {
        if (inputStream_ == 0)
            return false;
        if (c != std::istream::traits_type::eof())
            inputStream_->putback(c);
        else
            return false;
        if (c == '\n')
        {
            row_--;
            column_ = prevColumn_;
        }
        else
            column_--;
        return true;
    }
public:
    void setInputStream(std::istream *inputStream)
    {
        inputStream_ = inputStream;
        rewindInputStream();
    }
    void rewindInputStream()
    {
        if (inputStream_ != 0)
        {
            inputStream_->clear();
            inputStream_->seekg(0);
        }
        row_ = 1;
        column_ = 1;
        prevColumn_ = 1;
    }
    unsigned long getRow() const
    {
        return row_;
    }
    unsigned int getColumn() const
    {
        return column_;
    }
};

} // namespace IniFile

#endif

